/**
 * @file FirmwareVolume.c
 * 
 * @author https://ay123.net 
 * @version 0.1
 * @date 2023-10-29
 * 
 * @copyright Copyright (c) 2015 - 2023
 * 
 */

#include <Uefi.h>
#include <Library/PcdLib.h>
#include <Library/UefiLib.h>
#include <Pi/PiFirmwareVolume.h>
#include <Pi/PiFirmwareFile.h>
#include <Protocol/FirmwareVolume2.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>

#define AY123_FV_EXAMPLE_1  1
#define AY123_FV_EXAMPLE_2  0

GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiTestBinGuid = {0x944cadd5, 0x7c14, 0x462f, {0xaa, 0x96,0x29, 0x8f, 0x20, 0x04, 0xe0, 0xb0}};

VOID Ay123HexDump (UINT8 *Buffer, UINT8 RowNum)
{
  UINT8   Cols;
  UINT8   Rows;

  for (Rows = 0; Rows < RowNum; Rows ++) {
    for (Cols = 0; Cols < 16; Cols ++) {
      Print (L"%2X ", Buffer[Cols+Rows*16]);
    }

    Print (L"  ");

    for (Cols = 0; Cols < 16; Cols ++) {
      Print (L"%c", Buffer[Cols+Rows*16]);
    }
    Print (L"\n\r");
  }
  Print (L"\n\r");
}


EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_FIRMWARE_VOLUME2_PROTOCOL         *FwVol;
  EFI_STATUS                            Status;
  EFI_HANDLE                            *HandleBuffer;
  UINTN                                 NumberOfHandles;
  UINTN                                 Index;
  UINT32                                FvStatus;
  UINTN                                 Size;
  UINT8                                 *Buffer = NULL;

  FwVol = NULL;

  ///
  /// Locate FV protocol.
  ///
  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiFirmwareVolume2ProtocolGuid,
                  NULL,
                  &NumberOfHandles,
                  &HandleBuffer
                  );
  if (EFI_ERROR(Status)) {
    Print (L"No Efi Firmware Volume Protocol available.\n");
    return EFI_UNSUPPORTED;
  } else {
    Print (L"Efi Firmware Volume Protocol is loaded, num:%d.\n", NumberOfHandles);
  }

  for (Index = 0; Index < NumberOfHandles; Index ++) {
    Status = gBS->HandleProtocol(HandleBuffer[Index], &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol);
    if (!EFI_ERROR(Status)) {

#if defined(AY123_FV_EXAMPLE_1) && (AY123_FV_EXAMPLE_1 == 1)
      EFI_FV_FILETYPE           FileType;
      EFI_FV_FILE_ATTRIBUTES    Attributes;
      Status = FwVol->ReadFile (
                            FwVol,
                            &gUefiShellFileGuid,
                            (VOID**)&Buffer,
                            &Size,
                            &FileType,
                            &Attributes,
                            &FvStatus
                            );
      if (!EFI_ERROR(Status)) {

        Print (L"File Size = %ld\n\r", Size);
        Print (L"File Type = %d\n\r", FileType);
        Print (L"File Attributes = %8X\n\r", Attributes);
        Print (L"File Buffer:\n\r");
        for (Index = 0; Index < 64; Index ++) {
          if ((Index % 16) == 0 && Index > 0) {
            Print (L"\n\r");
          }
          Print (L"%2X ", Buffer[Index]);
        }
        Print (L"\n\r");
      }
#endif

#if defined(AY123_FV_EXAMPLE_2) && (AY123_FV_EXAMPLE_2 == 1)
      UINTN SectionInstance = 0;

      while (Status == EFI_SUCCESS)
      {
        Status = FwVol->ReadSection (
                              FwVol,
                              &gEfiTestBinGuid,
                              EFI_SECTION_RAW,
                              SectionInstance,
                              (VOID**)&Buffer,
                              &Size,
                              &FvStatus
                              );
        if (!EFI_ERROR(Status)) {
          Print (L"File Size = %ld\n\r", Size);
          Print (L"File Buffer:\n\r");
          Ay123HexDump(Buffer, 3);
        }
        SectionInstance ++;
      }
#endif
      return EFI_SUCCESS;
    }
  }

  return EFI_SUCCESS;
}
